package com.yugao.fintech.framework.assistant.crypto;

import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import com.yugao.fintech.framework.assistant.core.StringUtils;
import com.yugao.fintech.framework.assistant.core.exception.Assert;
import com.yugao.fintech.framework.assistant.core.exception.UtilException;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * AES模式下，key必须为16位或者32位
 */
public class AesCrypto {
    private static final String IV_KEY = "bXPK6s6lCMnB1JLW";

    private final AES aes;

    public AesCrypto(String secretKey, Mode mode, Padding padding) {
        Assert.notNull(mode, "aes mode is null");
        Assert.notNull(padding, "aes padding is null");
        this.aes = getAes(secretKey, mode, padding);
    }

    public AesCrypto(String secretKey) {
        this.aes = getAes(secretKey);
    }

    /**
     * 检查密钥
     */
    public static void checkSecretKey(String secretKey) {
        if (StringUtils.isEmpty(secretKey)) {
            throw new UtilException("非法密钥");
        }
        if (secretKey.length() != 16 && secretKey.length() != 32) {
            throw new UtilException("secretKey length only is 16 or 32");
        }
    }

    public String decrypt(String data) {
        if (StringUtils.isEmpty(data)) {
            return data;
        }
        byte[] decryptDataBase64 = aes.decrypt(data);
        return new String(decryptDataBase64, StandardCharsets.UTF_8);
    }


    public String encrypt(String data) {
        if (StringUtils.isEmpty(data)) {
            return data;
        }
        return aes.encryptBase64(data, StandardCharsets.UTF_8);
    }

    private static AES getAes(String secretKey, Mode mode, Padding padding) {
        checkSecretKey(secretKey);
        AES aes;
        if (Mode.CBC == mode) {
            aes = new AES(mode, padding,
                    new SecretKeySpec(secretKey.getBytes(), "AES"),
                    new IvParameterSpec(IV_KEY.getBytes()));
        } else {
            aes = new AES(mode, padding,
                    new SecretKeySpec(secretKey.getBytes(), "AES"));
        }
        return aes;
    }

    private static AES getAes(String secretKey) {
        return getAes(secretKey, Mode.CBC, Padding.ZeroPadding);
    }
}
